// 操作系统漏洞快扫模式目前展示在内部使用

package FastScan

import (
	_ "github.com/go-sql-driver/mysql"
	"database/sql"
	"fmt"
    "strings"
    "bytes"
	"os/exec"
	"strconv"
	"regexp"
    // "reflect"
)
 
var (
    dbhostsip  = "172.17.20.121:3306"
    dbusername = "root"
    dbpassword = ""
    dbname     = "kylincve"
)

func checkerr(err error){  
	if err!=nil{
		fmt.Printf("%c[%d;%d;%dm%s%c[0m", 0x1B, 0, 0, 31, "", 0x1B)
		fmt.Printf("%c[%d;%d;%dm%s%c[0m\n", 0x1B, 0, 0, 31, err, 0x1B)
        return
	}
 
}

var (
	version0 = 0
	version1 = 1
	version2 = 2
)
func StringStrip(str string) int {
	if str == "" {
		return 0
	}
	str = strings.TrimSpace(str)
	reg := regexp.MustCompile(`[^\d]`)
	result:=reg.ReplaceAllString(str, "")
	result1,err:=strconv.Atoi(result)
	checkerr(err)
	return result1
}
func StrTrimSpace(v1str,v2str string )(v1,v2 string ){
	v1=strings.TrimSpace(v1str)
	v2=strings.TrimSpace(v2str)
	return
}
func comparSlice(v1slice,v2slice []string )int{
	for index,_ :=range v1slice{
		// fmt.Printf("%T",v1slice[index])
		v1sliceInt:=StringStrip(v1slice[index])
		v2sliceInt:=StringStrip(v2slice[index])
		if v1sliceInt > v2sliceInt{
			return version1
		}
		if v1sliceInt < v2sliceInt{
			return version2
		}
		if len(v1slice)-1 == index {
			return  version0
		}
	}
	return  version0
}

func comparSlice1(v1slice,v2slice []string,flas int  )int{
	for index,_ :=range v1slice{
		//按照正常逻辑v1slice 长度小
		if v1slice[index] > v2slice[index]{
			if flas == 2{
				return version2
			}
			return version1

		}
		if v1slice[index] < v2slice[index]{
			if flas == 2{
				return version1
			}
			return version2
		}
		if len(v1slice)-1 == index {
			if flas == 2{
				return version1
			}else if flas == 1{
				return version2
			}
		}
	}
	return  version0
}

func compareStrVer(v1,v2 string)(res int ){
	s1, s2 := StrTrimSpace(v1, v2)
	v1slice := strings.Split(s1,".")
	v2slice := strings.Split(s2,".")
	//长度不相等直接退出
	if len(v1slice) != len(v2slice){
		if len(v1slice) > len(v2slice){
			res=comparSlice1(v2slice,v1slice,2)
			return res
		}else{
			res=comparSlice1(v1slice,v2slice,1)
			return res
		}
	}else{
		res = comparSlice(v1slice, v2slice)
	}
	return res

}

 
func fastScan(dpkgInfo []string){
    dbinfo := strings.Join([]string{dbusername, ":", dbpassword, "@tcp(", dbhostsip, ")/", dbname, "?charset=utf8"}, "")
	db,err:=sql.Open("mysql",dbinfo)
	checkerr(err)
    // 设置最大连接数
    db.SetConnMaxLifetime(100)
    // 设置数据库最大的闲置连接数
    db.SetMaxIdleConns(10)

    //>>>dbInfo
	type info struct {
		id int `db:"id"`
        cve_no string `db: "cve_no"`
        role_level string `db: "role_level"`
        ubuntu_v4_status string `db: "ubuntu_v4_status"`
        version_v4_status string `db: "version_v4_status"`
        ubuntu_v4_edition string `db: "ubuntu_v4_edition"`
        kylin_v4_edition string `db: "kylin_v4_edition"`
        ubuntu_v10_status string `db: "ubuntu_v10_status"`
        version_v10_status string `db: "version_v10_status"`
        ubuntu_v10_edition string `db: "ubuntu_v10_edition"`
        kylin_v10_edition string `db: "kylin_v10_edition"`
        ubuntu_v10_1_status string `db: "ubuntu_v10_1_status"`
        version_v10_1_status string `db: "version_v10_1_status"`
        ubuntu_v10_1_edition string `db: "ubuntu_v10_1_edition"`
        kylin_v10_1_edition string `db: "kylin_v10_1_edition"`
        version_ubuntu_kylin_status string `db: "version_ubuntu_kylin_status"`
        ubuntu_kylin_edition string `db: "ubuntu_kylin_edition"`
        package_name string `db: "package_name"`
        publish_status string `db: "publish_status"`
        date string `db: "date"`
	}

    //预编译处理查询数据防止sql注入
	sqlStr :="SELECT * FROM kvsp_cvelist where package_name = ?"
    stmt, err := db.Prepare(sqlStr)
	checkerr(err)
    defer stmt.Close()
    for i:=0;i<len(dpkgInfo);i++{
        if i & 1 == 0 {
            rows, err := stmt.Query(dpkgInfo[i])
            checkerr(err)
            for rows.Next(){
                var s info
                err = rows.Scan(&s.id,&s.cve_no,&s.role_level,&s.ubuntu_v4_status,&s.version_v4_status,&s.ubuntu_v4_edition,&s.kylin_v4_edition,&s.ubuntu_v10_status,&s.version_v10_status,&s.ubuntu_v10_edition,&s.kylin_v10_edition,&s.ubuntu_v10_1_status,&s.version_v10_1_status,&s.ubuntu_v10_1_edition,&s.kylin_v10_1_edition,&s.version_ubuntu_kylin_status,&s.ubuntu_kylin_edition,&s.package_name,&s.publish_status ,&s.date)
                checkerr(err)
                dpkgInfoStr:=dpkgInfo[i+1]
                result:=PushCompareVersion(s.cve_no,dpkgInfoStr,s.ubuntu_v10_1_edition)
                if result==2{
					FastScanResult:="ID:"+s.cve_no+" level:"+s.package_name+" Role:"+s.role_level+" Security_Version:"+s.ubuntu_v10_1_edition+" Current_Version:"+dpkgInfoStr
					fmt.Printf("%c[%d;%d;%dm%s%c[0m\n", 0x1B, 0, 0, 32, FastScanResult, 0x1B)
                }
            }
            rows.Close()
         }
    }
}


//Push will Compare system package version
func PushCompareVersion(cve_no string,dpkgInfoStr string,ubuntu_v10_1_edition string)(result int){
    if  len(ubuntu_v10_1_edition)<2 {
        return
    }else{
        v1 := strings.ReplaceAll(dpkgInfoStr, "ubuntu", ".")
        v1  = strings.ReplaceAll(v1, "kylin", ".")
		v1  = strings.ReplaceAll(v1, "k", ".")
		buildDislodge:=strings.LastIndex(v1, "build")
		if buildDislodge !=-1 {
			v1=string([]byte(v1)[0:buildDislodge])	
		}
        v2 := strings.ReplaceAll(ubuntu_v10_1_edition, "ubuntu", ".")
        v2  = strings.ReplaceAll(v2, "kylin", ".")
        result=compareStrVer(v1,v2)
        return result

    }
}

func GetdpkgInfo(){
	cmdStr:="dpkg -l|awk '{print $2,$3}'"
	cmd := exec.Command("/bin/bash", "-c", cmdStr)
	var stdout, stderr bytes.Buffer
	cmd.Stdout = &stdout // 标准输出
	cmd.Stderr = &stderr // 标准错误
	err := cmd.Run()
	outStr, errStr := string(stdout.Bytes()), string(stderr.Bytes())
	if len(errStr)!=0{
		fmt.Printf(errStr)
	}
	outStr=strings.TrimSpace(outStr)
	if err != nil {
		fmt.Println("cmd.Run() failed with %s\n", errStr)
	}
    dpkgInfo := strings.Fields(outStr)
    dpkgInfo = append(dpkgInfo[5:])
    fastScan(dpkgInfo)

}